Notes / Questions

  • The complete dataset includes 235 observations

    • excluding region NA there are 201 observations left

    • excluding incomplete responses there are 199 observations left

    • excluding high income countries there are 176 observations left

Figure 1

Identifying populations for latent TB infection (LTBI) testing and TB preventive treatment after exclusion of active TB. Mapping according to WHO guidelines (see WHO consolidated guidelines, Table 1, page xi).

df1 <- df %>%
  select(
    record_id, region, tpt_eligible_adult___6, tpt_lt12m, tpt_ge1y, tpt_g11y_tb, tpt_peds_lt5,
    tpt_peds_ge9, tpt_adults, tpt_hrcontacts, tpt_atrisk___3:tpt_atrisk___13, HBC_ANY, HBC_TB,
    HBC_TB_HIV, HBC_DR_TB, tbhiv_integration.factor, integration_oth, Income_group, Prev_cat.factor) %>% 
  mutate(
    across(
      c(tpt_lt12m, tpt_g11y_tb, tpt_peds_lt5, tpt_ge1y, tpt_peds_ge9, 
        tpt_adults,tpt_hrcontacts),
      ~ as.factor(if_else(is.na(.), "0", as.character(.)))), #manually checked - they dont provide TPT at all, so would be "No" but they had to skip the question
    across(
      c(tpt_peds_lt5, tpt_peds_ge9, tpt_adults, tpt_hrcontacts),
      ~ as.factor(if_else(. == "2", "0", .)))) %>% #"No" was coded as 2 here
  rename(
    '< 5 years old' = tpt_peds_lt5,
    '5-10 years old' = tpt_peds_ge9,
    '> 10 years old' = tpt_adults,
    'Contacts of MDR-TB Patients' = tpt_hrcontacts,
    'People on anti-TNF treatment' = tpt_atrisk___3,
    'People preparing for transplant' = tpt_atrisk___4,
    'People with silicosis' = tpt_atrisk___5,
    Prisoners = tpt_atrisk___6,
    'Health workers' = tpt_atrisk___7,
    'Immigrants (TB burden country)' = tpt_atrisk___8,
    Homeless = tpt_atrisk___9,
    'Drug users' = tpt_atrisk___10,
    'Alcohol users' = tpt_atrisk___11,
    'Tabacco users' = tpt_atrisk___12,
    'Underweight' = tpt_atrisk___13,
    ' > 10 years old' = tpt_eligible_adult___6, #add space to distingush it from the same variable in the other category
    'Infants (in contact with person with TB)' = tpt_lt12m,
    '> 10 years old (high TB setting)' = tpt_ge1y,
    'children LWH (completed TB treatment)' = tpt_g11y_tb,
    'Level of integration' = tbhiv_integration.factor,
    'Income Level' = Income_group, 
    'HIV Prevalence' = Prev_cat.factor) %>% 
  mutate(across(
    .cols = everything(),
    .fns = ~ as.factor(as.character(.)))) %>% 
  pivot_longer(
    cols = 
      -c(record_id, region, HBC_ANY, HBC_TB, HBC_TB_HIV, HBC_DR_TB, `Level of integration`,
         integration_oth, `Income Level`, `HIV Prevalence`),
    names_to = "variable",
    values_to = "category") %>% 
  mutate(
    category = factor(category, levels = c("0", "1", "3", "77"), 
                      labels = c("No", "Yes", "Don't know", "Not available")),
    who_group = factor(
      case_when(
        variable %in% c(" > 10 years old", #add a space to distinguish it from the same variable in the other category
                        "Infants (in contact with person with TB)", 
                        "> 10 years old (high TB setting)", 
                        "children LWH (completed TB treatment)") ~ "PLHIV",
        variable %in% c("< 5 years old",
                        "5-10 years old",
                        "> 10 years old",
                        "Contacts of MDR-TB Patients") ~ "Household contacts",
        variable %in% c("People on anti-TNF treatment",
                        "People preparing for transplant",
                        "Prisoners",
                        "People with silicosis",
                        "Health workers",
                        "Immigrants (TB burden country)",
                        "Homeless",
                        "Drug users",
                        "Alcohol users",
                        "Tabacco users",
                        "Underweight") ~ "Other people at risk", 
        TRUE ~ "Others"),
      levels = c("PLHIV", "Household contacts", "Other people at risk")))
fig1("")

Stratified by high burden countries (all)

fig1("HBC")

Stratified by high burden countries (any vs. no)

fig1("HBC_ANY")

Stratified by region

fig1("region")

Stratified by level of integration

fig1("Level of integration")

Note, there are only three clinics that responded “Other”. These are their written responses, they are excluded in the plot:

df1_int_OTH <- df1 %>% 
  filter(`Level of integration` == "Other") %>% 
  select(record_id, integration_oth) %>% 
  distinct()

df %>% filter(record_id %in% df1_int_OTH$record_id) %>% 
  select(name, country, region.factor) %>% 
  cbind(df1_int_OTH) %>%
  kable() %>% 
  kable_styling(full_width = T)
name country region.factor record_id integration_oth
Instituto Nacional de Ciencias Medicas y Nutricion Salvador Zubiran MEX CCASAnet (Latin America) 102 We start and follow up both, but the TB medication and DOT is provided in other clinics according where the patient lives
Kanyama ZMB Southern Africa 418 TB diagnosis in ART clinic(treatment in TB corner)
Centre Hospitalier Universitaire Gabriel Touré - Pediatric MLI West Africa 523 Soins du VIH a la clinique et traitement de la tuberculose hors site uniquement

Stratified by Income Level

fig1("Income Level")

Stratified by HIV Prevalence

fig1("HIV Prevalence")

Figure 2

Barriers to TPT administration: **11.15 What are the most important barriers to initiating patients with HIV on TPT at this facility? Check all that apply**  

df2 <- df %>% 
  select(record_id, region, tpt_barriers___77:tpt_barriers___88, HBC_ANY, HBC_TB,
    HBC_TB_HIV, HBC_DR_TB, tbhiv_integration.factor, Income_group, Prev_cat.factor) %>%
  rename(
         'No barriers' = tpt_barriers___77,
         'Medication availability' = tpt_barriers___1,
         'LTBI Testing stockouts' = tpt_barriers___2,
         'Availability of diagnostics active TB' = tpt_barriers___3,
         'Concerns drug resistance' = tpt_barriers___4,
         'Increased workload' = tpt_barriers___5,
         'Patients refuse TPT' = tpt_barriers___6,
         'Access to HIV care service delivery'= tpt_barriers___7,
         'Other barriers' = tpt_barriers___88,
         'Level of integration' = tbhiv_integration.factor,
         'Income Level' = Income_group, 
         'HIV Prevalence' = Prev_cat.factor) %>% 
  mutate(across(everything(), ~ as.factor(.))) %>% 
  pivot_longer(cols = -c(record_id, region, HBC_ANY, HBC_TB, HBC_TB_HIV, HBC_DR_TB, `Level of integration`, `Income Level`, `HIV Prevalence`),
               names_to = "variable",
               values_to = "category") %>% 
  mutate(variable = as.factor(variable),
         fct_relevel(variable, "No barriers"),
         category = as.factor(ifelse(category == 1, "Yes", "No")))
fig2("")
Figure 2: Proportion of clinics responding to the questions regarding specific boundaries to initiating patients with HIV on TPT at the clinic. Also, if somebody in the clinic received formal training for TPT.

Figure 2: Proportion of clinics responding to the questions regarding specific boundaries to initiating patients with HIV on TPT at the clinic. Also, if somebody in the clinic received formal training for TPT.

Stratified by high burden countries

fig2("HBC")

Stratified by high burden countries (any vs. no)

fig2("HBC_ANY")

Stratified by region

fig2("region")

Stratified by level of integration

fig2("Level of integration")

Stratified by Income Level

fig2("Income Level")

Stratified by HIV Prevalence

fig2("HIV Prevalence")

Figure 3

  • Proportion of sites who responded “Yes” to the following question: “11.6 Does this HIV clinic (or a co-located TB clinic) currently provide TB preventive therapy (TPT)?”.

  • The points are located at the coordinates from the sites (from Google Maps).

coords <- read.csv("../data_clean/coordinates_sites.csv") %>%
  separate(coord, into = c("lat", "long"), sep = ",", convert = TRUE) %>% 
  filter(record_id %in% df$record_id)

world <- map_data("world") 

df3a <- df %>% 
  select(country, region_exact, tpt_prov) %>% 
  group_by(region_exact) %>% 
  summarise(prop_tpt = mean(tpt_prov == 1, na.rm = TRUE))

df3 <- df %>% 
  select(record_id, country, region, region_exact)  %>% 
  left_join(df3a, by = "region_exact") %>%   
  mutate(region = case_when(
    country == "ARG" ~ "Argentina",
    country == "AUS" ~ "Australia",
    country == "BDI" ~ "Burundi",
    country == "BEN" ~ "Benin",
    country == "BFA" ~ "Burkina Faso",
    country == "BRA" ~ "Brazil",
    country == "CHL" ~ "Chile",
    country == "CHN" ~ "China",
    country == "CIV" ~ "Ivory Coast",
    country == "CMR" ~ "Cameroon",
    country == "COD" ~ "Democratic Republic of the Congo",
    country == "COG" ~ "Republic of the Congo",
    country == "GHA" ~ "Ghana",
    country == "HND" ~ "Honduras",
    country == "HTI" ~ "Haiti",
    country == "IDN" ~ "Indonesia",
    country == "IND" ~ "India",
    country == "JPN" ~ "Japan",
    country == "KEN" ~ "Kenya",
    country == "KHM" ~ "Cambodia",
    country == "KOR" ~ "South Korea",
    country == "LSO" ~ "Lesotho",
    country == "MEX" ~ "Mexico",
    country == "MLI" ~ "Mali",
    country == "MOZ" ~ "Mozambique",
    country == "MWI" ~ "Malawi",
    country == "MYS" ~ "Malaysia",
    country == "NGA" ~ "Nigeria",
    country == "PER" ~ "Peru",
    country == "PHL" ~ "Philippines",
    country == "RWA" ~ "Rwanda",
    country == "SGP" ~ "Singapore",
    country == "TGO" ~ "Togo",
    country == "THA" ~ "Thailand",
    country == "TWN" ~ "Taiwan",
    country == "TZA" ~ "Tanzania",
    country == "UGA" ~ "Uganda",
    country == "VNM" ~ "Vietnam",
    country == "ZAF" ~ "South Africa",
    country == "ZMB" ~ "Zambia",
    country == "ZWE" ~ "Zimbabwe",
    TRUE ~ NA_character_))  
  
worldSubset <- left_join(world, df3, by = "region", relationship =  "many-to-many") %>% 
  filter(region != "Antarctica")

plain <- theme(
  axis.text = element_blank(),
  axis.line = element_blank(),
  axis.ticks = element_blank(),
  panel.border = element_blank(),
  panel.grid = element_blank(),
  axis.title = element_blank(),
  panel.background = element_rect(fill = "white"),
  plot.title = element_text(hjust = 0.5))

my_colors <- c("value1" = "#color1", 
               "value2" = "#color2",
               "value3" = "#color3",
               "value4" = "#color4",
               "value5" = "#color5")  # Add a color for NA values

worldSubset %>% 
  ggplot(aes(x = long, y = lat)) +
  coord_fixed(1.3) +
  geom_polygon(aes(fill = prop_tpt, group = group)) +
  scale_fill_gradient(low = "#D8F3DC", high = "#3DAC78", limits = c(0.9, 1), na.value = "#CECECD") +
  geom_point(data = coords, aes(x = long, y = lat), color = wes_palette("GrandBudapest1")[2], size = .7, position = "jitter") +
  plain +
  labs(fill = "", x = "", y = "")

Figure 4

Numbers of newly initiated TPT and newly intitated ART in a subset of sites, 2018-2022 (data from COVID-TB survey, MR214).

  • Nicolas will provide the figure

Figure 5

Available treatment options of TPT regimens.

  • This is the table of the survey for reference.

fig5("")

Supplementary table

I can change the order of the table for the final version (as proposed by Lukas) i.e. categories as columns. I omitted this for the moment because this option here is easier to code.

table1(~ `6-month isoniazid (6H)` + `9-month isoniazid (9H)` + `12-month isoniazid (12H)` + `36/Lifetime isoniazid (36/Lifetime H)` + `3-month rifampicin (3R)` + `4-month rifampicin (4R)` +  `3-month isoniazid-rifampicin (3HR)` + `Once-weekly isoniazid-rifapentine for 12 weeks (3HP)` + `Once-daily isoniazid-rifapentine for 1 month (1HP)` + `Regimens for MDR-TB exposure` + Other | HBC_ANY, 
       overall = c(left = "All"),
       data = df5,
       topclass="Rtable1-zebra",
       caption = "Available treatment options of TPT regimens")
Available treatment options of TPT regimens
All
(N=176)
HBC
(N=138)
Not HBC
(N=38)
6-month isoniazid (6H)
Adults 29 (16.5%) 26 (18.8%) 3 (7.9%)
Both 91 (51.7%) 72 (52.2%) 19 (50.0%)
Children 33 (18.8%) 24 (17.4%) 9 (23.7%)
Don't know 2 (1.1%) 1 (0.7%) 1 (2.6%)
None 21 (11.9%) 15 (10.9%) 6 (15.8%)
9-month isoniazid (9H)
Adults 13 (7.4%) 10 (7.2%) 3 (7.9%)
Both 6 (3.4%) 4 (2.9%) 2 (5.3%)
Children 1 (0.6%) 0 (0%) 1 (2.6%)
Don't know 11 (6.3%) 9 (6.5%) 2 (5.3%)
None 145 (82.4%) 115 (83.3%) 30 (78.9%)
12-month isoniazid (12H)
Adults 8 (4.5%) 8 (5.8%) 0 (0%)
Both 2 (1.1%) 2 (1.4%) 0 (0%)
Children 1 (0.6%) 0 (0%) 1 (2.6%)
Don't know 11 (6.3%) 9 (6.5%) 2 (5.3%)
None 154 (87.5%) 119 (86.2%) 35 (92.1%)
36/Lifetime isoniazid (36/Lifetime H)
Adults 2 (1.1%) 2 (1.4%) 0 (0%)
Both 1 (0.6%) 0 (0%) 1 (2.6%)
Children 1 (0.6%) 1 (0.7%) 0 (0%)
Don't know 17 (9.7%) 14 (10.1%) 3 (7.9%)
None 155 (88.1%) 121 (87.7%) 34 (89.5%)
3-month rifampicin (3R)
Adults 5 (2.8%) 4 (2.9%) 1 (2.6%)
Both 3 (1.7%) 3 (2.2%) 0 (0%)
Children 3 (1.7%) 2 (1.4%) 1 (2.6%)
Don't know 14 (8.0%) 11 (8.0%) 3 (7.9%)
None 151 (85.8%) 118 (85.5%) 33 (86.8%)
4-month rifampicin (4R)
Adults 4 (2.3%) 4 (2.9%) 0 (0%)
Both 5 (2.8%) 5 (3.6%) 0 (0%)
Children 3 (1.7%) 3 (2.2%) 0 (0%)
Don't know 14 (8.0%) 11 (8.0%) 3 (7.9%)
None 150 (85.2%) 115 (83.3%) 35 (92.1%)
3-month isoniazid-rifampicin (3HR)
Adults 16 (9.1%) 13 (9.4%) 3 (7.9%)
Both 15 (8.5%) 12 (8.7%) 3 (7.9%)
Children 18 (10.2%) 17 (12.3%) 1 (2.6%)
Don't know 12 (6.8%) 10 (7.2%) 2 (5.3%)
None 115 (65.3%) 86 (62.3%) 29 (76.3%)
Once-weekly isoniazid-rifapentine for 12 weeks (3HP)
Adults 79 (44.9%) 71 (51.4%) 8 (21.1%)
Both 26 (14.8%) 19 (13.8%) 7 (18.4%)
Children 5 (2.8%) 4 (2.9%) 1 (2.6%)
Don't know 5 (2.8%) 3 (2.2%) 2 (5.3%)
None 61 (34.7%) 41 (29.7%) 20 (52.6%)
Once-daily isoniazid-rifapentine for 1 month (1HP)
Adults 7 (4.0%) 6 (4.3%) 1 (2.6%)
Both 4 (2.3%) 2 (1.4%) 2 (5.3%)
Children 2 (1.1%) 2 (1.4%) 0 (0%)
Don't know 12 (6.8%) 8 (5.8%) 4 (10.5%)
None 151 (85.8%) 120 (87.0%) 31 (81.6%)
Regimens for MDR-TB exposure
Adults 3 (1.7%) 3 (2.2%) 0 (0%)
Both 6 (3.4%) 5 (3.6%) 1 (2.6%)
Children 4 (2.3%) 3 (2.2%) 1 (2.6%)
Don't know 19 (10.8%) 14 (10.1%) 5 (13.2%)
None 144 (81.8%) 113 (81.9%) 31 (81.6%)
Other
Both 2 (1.1%) 1 (0.7%) 1 (2.6%)
Children 1 (0.6%) 0 (0%) 1 (2.6%)
Don't know 21 (11.9%) 14 (10.1%) 7 (18.4%)
None 152 (86.4%) 123 (89.1%) 29 (76.3%)

Stratified by high burden countries

Caveat for all three stratification plots: These are the top 4 treatments overall now stratified, not necessarily the top 4 per stratum.

fig5("HBC")

Stratified by high burden countries (any vs. no)

fig5("HBC_ANY")

Stratified by region

fig5("region")

Stratified by level of integration

fig5("Level of integration")

Stratified by Income Level

fig5("Income Level")

Stratified by HIV Prevalence

fig5("HIV Prevalence")

Table 1

df6 <- df %>% 
  select(record_id, region, HBC_ANY, adultped.factor, rural.factor, level.factor, tbtrt.factor, tbhiv_integration.factor)  %>% 
  rename(`Population the center serves` = adultped.factor,
         `Facility location` = rural.factor,
         `Facility level of care`  = level.factor,
         `TB treatment for PLHIV` = tbtrt.factor,
         `Level of integrated TB/HIV services` = tbhiv_integration.factor) %>% 
    mutate(`Facility level of care` = fct_drop(`Facility level of care`),
           `Facility location` = fct_drop(`Facility location`))

levels(df6$`Level of integrated TB/HIV services`) <- c("Full-integration (TB diagnostics and TB treatment)", "Partial integration (TB diagnostics or TB treatment)", "Not integrated", "Other")

levels(df6$`Population the center serves`) <- c("Adults", "Children", "Both")

table1(~ `Population the center serves` + `Facility location` + `Facility level of care` + `TB treatment for PLHIV` + `Level of integrated TB/HIV services` |  HBC_ANY + region, data = df6,
       overall = c(left = "All"),
       topclass="Rtable1-zebra",
       caption = "Site characteristics stratified by region and by classification in High Burden Countries (HBC) for in any of the three categories according to WHO definition.")
Site characteristics stratified by region and by classification in High Burden Countries (HBC) for in any of the three categories according to WHO definition.
All
HBC
Not HBC
Africa
(N=145)
Asia-Pacific
(N=23)
Latin America
(N=8)
Africa
(N=115)
Asia-Pacific
(N=19)
Latin America
(N=4)
Africa
(N=30)
Asia-Pacific
(N=4)
Latin America
(N=4)
Population the center serves
Adults 12 (8.3%) 15 (65.2%) 4 (50.0%) 6 (5.2%) 12 (63.2%) 2 (50.0%) 6 (20.0%) 3 (75.0%) 2 (50.0%)
Children 12 (8.3%) 4 (17.4%) 2 (25.0%) 3 (2.6%) 4 (21.1%) 2 (50.0%) 9 (30.0%) 0 (0%) 0 (0%)
Both 118 (81.4%) 4 (17.4%) 2 (25.0%) 103 (89.6%) 3 (15.8%) 0 (0%) 15 (50.0%) 1 (25.0%) 2 (50.0%)
Missing 3 (2.1%) 0 (0%) 0 (0%) 3 (2.6%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Facility location
Urban 62 (42.8%) 19 (82.6%) 8 (100%) 40 (34.8%) 17 (89.5%) 4 (100%) 22 (73.3%) 2 (50.0%) 4 (100%)
Mostly urban 16 (11.0%) 3 (13.0%) 0 (0%) 10 (8.7%) 1 (5.3%) 0 (0%) 6 (20.0%) 2 (50.0%) 0 (0%)
Mostly rural 22 (15.2%) 0 (0%) 0 (0%) 22 (19.1%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Rural 43 (29.7%) 1 (4.3%) 0 (0%) 41 (35.7%) 1 (5.3%) 0 (0%) 2 (6.7%) 0 (0%) 0 (0%)
Missing 2 (1.4%) 0 (0%) 0 (0%) 2 (1.7%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Facility level of care
Health centre 91 (62.8%) 4 (17.4%) 0 (0%) 73 (63.5%) 4 (21.1%) 0 (0%) 18 (60.0%) 0 (0%) 0 (0%)
District hospital 16 (11.0%) 0 (0%) 0 (0%) 16 (13.9%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Regional, provincial or university hospital 30 (20.7%) 19 (82.6%) 8 (100%) 18 (15.7%) 15 (78.9%) 4 (100%) 12 (40.0%) 4 (100%) 4 (100%)
Missing 8 (5.5%) 0 (0%) 0 (0%) 8 (7.0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
TB treatment for PLHIV
Provided in HIV Clinic 91 (62.8%) 12 (52.2%) 6 (75.0%) 79 (68.7%) 10 (52.6%) 2 (50.0%) 12 (40.0%) 2 (50.0%) 4 (100%)
In same health facility (but not at HIV clinic) 44 (30.3%) 8 (34.8%) 2 (25.0%) 33 (28.7%) 8 (42.1%) 2 (50.0%) 11 (36.7%) 0 (0%) 0 (0%)
Only offsite (referral) 9 (6.2%) 3 (13.0%) 0 (0%) 3 (2.6%) 1 (5.3%) 0 (0%) 6 (20.0%) 2 (50.0%) 0 (0%)
Not available 1 (0.7%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 1 (3.3%) 0 (0%) 0 (0%)
Level of integrated TB/HIV services
Full-integration (TB diagnostics and TB treatment) 94 (64.8%) 11 (47.8%) 3 (37.5%) 79 (68.7%) 9 (47.4%) 2 (50.0%) 15 (50.0%) 2 (50.0%) 1 (25.0%)
Partial integration (TB diagnostics or TB treatment) 39 (26.9%) 11 (47.8%) 4 (50.0%) 30 (26.1%) 9 (47.4%) 2 (50.0%) 9 (30.0%) 2 (50.0%) 2 (50.0%)
Not integrated 10 (6.9%) 1 (4.3%) 0 (0%) 5 (4.3%) 1 (5.3%) 0 (0%) 5 (16.7%) 0 (0%) 0 (0%)
Other 2 (1.4%) 0 (0%) 1 (12.5%) 1 (0.9%) 0 (0%) 0 (0%) 1 (3.3%) 0 (0%) 1 (25.0%)

Original factor levels Level of integrated TB/HIV services:

  • [1] “Full-integration (TB diagnostics and TB treatment under same roof or same facility than HIV care)”

  • [2] “Partial integration (either TB diagnostics or TB treatment available under same roof or same facility than HIV care)”

  • [3] “Not integrated”

  • [4] “Other, specify: {integration_oth}”

Table 2

df_ltbi_testing <- df %>% 
  select(record_id, ltbi_testing___0, ltbi_testing___1, ltbi_testing___2, ltbi_testing___88, ltbi_testing_oth)  %>% 
  mutate(`Ltbi testing` = case_when(ltbi_testing___0 == 1 ~ "None",
                                    ltbi_testing___1 == 1 & ltbi_testing___2 == 1 ~ "Both",
                                    ltbi_testing___1 == 1 ~ "Interferon-Gamma Release Assays (IGRAs) blood test",
                                    ltbi_testing___2 == 1 ~ "Tuberculin Skin Test (TST)",
                                    ltbi_testing_oth != "" ~ "Other",
                                    TRUE ~ NA)) %>% 
  select(record_id, `Ltbi testing`)

df7 <- df %>% 
  select(record_id, region, HBC_ANY, tb_symptom_screen.factor, screen_cough.factor, screen_fever.factor, screen_nightsweats.factor, screen_weightloss.factor, screen_contact.factor, screen_fatigue.factor, screen_oth.factor, ltbi_ligibility.factor, tpt_prov.factor, tpt_training.factor) %>% 
  left_join(df_ltbi_testing, by = "record_id") %>% 
  rename(`TB symptom screening for enrolled patients?` = tb_symptom_screen.factor,
         `Cough screening` = screen_cough.factor,
         `Fever screening`  = screen_fever.factor,
         `Night sweats screening` = screen_nightsweats.factor,
         `Weight loss screening` = screen_weightloss.factor,
         `History of contact with a TB patient screening` = screen_contact.factor,
         `Fatigue/lethargy (or decreased playfulness in children) screening` = screen_fatigue.factor,
         Other = screen_oth.factor,
         `LTBI to check eligibility of PLHIV to receive TPT`= ltbi_ligibility.factor,
         `TPT currently provided in-house or at co-located TB clinic` = tpt_prov.factor,
         `Anyone attended a formal training on TPT provision` = tpt_training.factor)  

levels(df7$`TB symptom screening for enrolled patients?`) <- c("Yes, at the time of enrollment into HIV care at this facility only", "Yes, at every appointment", "Other", "No")

table1(~ `TB symptom screening for enrolled patients?` + `Cough screening` + `Fever screening` + `Night sweats screening` + `Weight loss screening` + `History of contact with a TB patient screening` + `Fatigue/lethargy (or decreased playfulness in children) screening` + Other +`LTBI to check eligibility of PLHIV to receive TPT` + `TPT currently provided in-house or at co-located TB clinic` + `Anyone attended a formal training on TPT provision`|  HBC_ANY + region, data = df7,
       overall = c(left = "All"),
       topclass="Rtable1-zebra",
       caption = "Availability of screening and testing services stratified by region and by classification in High Burden Countries (HBC) in any of the three categories according to WHO definition.")
Availability of screening and testing services stratified by region and by classification in High Burden Countries (HBC) in any of the three categories according to WHO definition.
All
HBC
Not HBC
Africa
(N=145)
Asia-Pacific
(N=23)
Latin America
(N=8)
Africa
(N=115)
Asia-Pacific
(N=19)
Latin America
(N=4)
Africa
(N=30)
Asia-Pacific
(N=4)
Latin America
(N=4)
TB symptom screening for enrolled patients?
Yes, at the time of enrollment into HIV care at this facility only 36 (24.8%) 12 (52.2%) 4 (50.0%) 30 (26.1%) 8 (42.1%) 2 (50.0%) 6 (20.0%) 4 (100%) 2 (50.0%)
Yes, at every appointment 108 (74.5%) 10 (43.5%) 3 (37.5%) 85 (73.9%) 10 (52.6%) 1 (25.0%) 23 (76.7%) 0 (0%) 2 (50.0%)
Other 1 (0.7%) 1 (4.3%) 1 (12.5%) 0 (0%) 1 (5.3%) 1 (25.0%) 1 (3.3%) 0 (0%) 0 (0%)
No 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Cough screening
Yes 145 (100%) 23 (100%) 8 (100%) 115 (100%) 19 (100%) 4 (100%) 30 (100%) 4 (100%) 4 (100%)
No 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Dont Know 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Fever screening
Yes 145 (100%) 23 (100%) 8 (100%) 115 (100%) 19 (100%) 4 (100%) 30 (100%) 4 (100%) 4 (100%)
No 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Dont Know 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Night sweats screening
Yes 145 (100%) 21 (91.3%) 8 (100%) 115 (100%) 17 (89.5%) 4 (100%) 30 (100%) 4 (100%) 4 (100%)
No 0 (0%) 2 (8.7%) 0 (0%) 0 (0%) 2 (10.5%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Dont Know 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Weight loss screening
Yes 145 (100%) 23 (100%) 8 (100%) 115 (100%) 19 (100%) 4 (100%) 30 (100%) 4 (100%) 4 (100%)
No 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Dont Know 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
History of contact with a TB patient screening
Yes 139 (95.9%) 22 (95.7%) 6 (75.0%) 111 (96.5%) 18 (94.7%) 3 (75.0%) 28 (93.3%) 4 (100%) 3 (75.0%)
No 6 (4.1%) 1 (4.3%) 2 (25.0%) 4 (3.5%) 1 (5.3%) 1 (25.0%) 2 (6.7%) 0 (0%) 1 (25.0%)
Dont Know 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Fatigue/lethargy (or decreased playfulness in children) screening
Yes 127 (87.6%) 20 (87.0%) 7 (87.5%) 102 (88.7%) 18 (94.7%) 4 (100%) 25 (83.3%) 2 (50.0%) 3 (75.0%)
No 17 (11.7%) 3 (13.0%) 0 (0%) 12 (10.4%) 1 (5.3%) 0 (0%) 5 (16.7%) 2 (50.0%) 0 (0%)
Dont Know 1 (0.7%) 0 (0%) 1 (12.5%) 1 (0.9%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 1 (25.0%)
Other
Yes 30 (20.7%) 3 (13.0%) 1 (12.5%) 22 (19.1%) 3 (15.8%) 1 (25.0%) 8 (26.7%) 0 (0%) 0 (0%)
No 103 (71.0%) 14 (60.9%) 4 (50.0%) 85 (73.9%) 10 (52.6%) 2 (50.0%) 18 (60.0%) 4 (100%) 2 (50.0%)
Dont Know 12 (8.3%) 6 (26.1%) 3 (37.5%) 8 (7.0%) 6 (31.6%) 1 (25.0%) 4 (13.3%) 0 (0%) 2 (50.0%)
LTBI to check eligibility of PLHIV to receive TPT
Yes 45 (31.0%) 10 (43.5%) 4 (50.0%) 34 (29.6%) 9 (47.4%) 3 (75.0%) 11 (36.7%) 1 (25.0%) 1 (25.0%)
No 95 (65.5%) 12 (52.2%) 4 (50.0%) 77 (67.0%) 9 (47.4%) 1 (25.0%) 18 (60.0%) 3 (75.0%) 3 (75.0%)
Missing 5 (3.4%) 1 (4.3%) 0 (0%) 4 (3.5%) 1 (5.3%) 0 (0%) 1 (3.3%) 0 (0%) 0 (0%)
TPT currently provided in-house or at co-located TB clinic
Yes 140 (96.6%) 22 (95.7%) 8 (100%) 111 (96.5%) 18 (94.7%) 4 (100%) 29 (96.7%) 4 (100%) 4 (100%)
No 5 (3.4%) 1 (4.3%) 0 (0%) 4 (3.5%) 1 (5.3%) 0 (0%) 1 (3.3%) 0 (0%) 0 (0%)
Anyone attended a formal training on TPT provision
Yes 123 (84.8%) 22 (95.7%) 4 (50.0%) 96 (83.5%) 18 (94.7%) 2 (50.0%) 27 (90.0%) 4 (100%) 2 (50.0%)
No 15 (10.3%) 0 (0%) 1 (12.5%) 13 (11.3%) 0 (0%) 0 (0%) 2 (6.7%) 0 (0%) 1 (25.0%)
Dont Know 2 (1.4%) 0 (0%) 3 (37.5%) 2 (1.7%) 0 (0%) 2 (50.0%) 0 (0%) 0 (0%) 1 (25.0%)
Missing 5 (3.4%) 1 (4.3%) 0 (0%) 4 (3.5%) 1 (5.3%) 0 (0%) 1 (3.3%) 0 (0%) 0 (0%)

Table 3

Preparing outcome variable

df6 <- df1 %>% 
  group_by(record_id, who_group) %>% 
  summarize(any_yes = ifelse(any(category == "Yes"), 1, 0), .groups = 'drop') %>% 
  left_join(df %>% select(record_id, tbhiv_integration.factor, Income_group, Prev_cat.factor, HBC_ANY, tpt_training.factor, level.factor), by = "record_id") %>% 
  rename(
    'Level of integration' = tbhiv_integration.factor,
    'Income Level' = Income_group, 
    'HIV Prevalence' = Prev_cat.factor,
    'High burden country' = HBC_ANY,
    'TPT training' = tpt_training.factor,
    'Facility level of care' = level.factor) %>% 
  mutate(`Income Level` = as.factor(`Income Level`),
         `Level of integration` = case_when(
           `Level of integration` == "Other" ~ NA, 
           TRUE~`Level of integration`)) 

df6$`Level of integration` <- relevel(df6$`Level of integration`, ref = "No integration")
df6$`Income Level` <- relevel(df6$`Income Level`, ref = "Low income")
df6$`HIV Prevalence` <- relevel(df6$`HIV Prevalence`, ref = "low (<1%)")
df6$`High burden country` <- relevel(df6$`High burden country`, ref = "Not HBC")
df6$`TPT training` <- relevel(df6$`TPT training`, ref = "No")
df6$`Facility level of care` <- relevel(df6$`Facility level of care`, ref = "Regional, provincial or university hospital")

plhiv <- df6 %>% filter(who_group == "PLHIV")
household <- df6 %>% filter(who_group == "Household contacts")
oPaR <- df6 %>% filter(who_group == "Other people at risk")

Reference Levels:

  • Level of integration: No integration

  • Income Level: Low income

  • HIV Prevalence: low (<1%)

  • TPT training: No training

  • acility level of care: Regional, provincial or university hospital

Outcome 1: Adherence to any of the recommendations for PLHIV.

m1 <- glm(any_yes ~ `Level of integration` + `Income Level` + `High burden country` + `TPT training` + `Facility level of care`,
          family = "binomial",
          data = plhiv)
summ(m1, confint = TRUE, exp = TRUE)
Observations 160 (16 missing obs. deleted)
Dependent variable any_yes
Type Generalized linear model
Family binomial
Link logit
𝛘²(9) 6.60
Pseudo-R² (Cragg-Uhler) 0.09
Pseudo-R² (McFadden) 0.07
AIC 103.58
BIC 134.34
exp(Est.) 2.5% 97.5% z val. p
(Intercept) 4.71 0.19 114.57 0.95 0.34
Level of integrationFull integration 1.96 0.17 22.01 0.55 0.59
Level of integrationPartial integration 0.97 0.09 10.08 -0.03 0.98
Income LevelLower middle income 1.24 0.29 5.31 0.29 0.77
Income LevelUpper middle income 0.59 0.10 3.59 -0.58 0.57
High burden countryHBC 1.31 0.33 5.19 0.39 0.70
TPT trainingYes 1.01 0.11 9.15 0.01 0.99
TPT trainingDont Know 0.89 0.03 23.97 -0.07 0.94
Facility level of careHealth centre 1.52 0.41 5.68 0.62 0.53
Facility level of careDistrict hospital 11116418.89 0.00 Inf 0.01 0.99
Standard errors: MLE

Outcome 2: Adherence to any of the recommendations for Household contacts.

m2 <- glm(any_yes ~ `Level of integration` + `Income Level` + `High burden country` + `TPT training` + `Facility level of care`,
          family = "binomial",
          data = household)
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summ(m2, confint = TRUE, exp = TRUE)
Observations 160 (16 missing obs. deleted)
Dependent variable any_yes
Type Generalized linear model
Family binomial
Link logit
𝛘²(9) 33.85
Pseudo-R² (Cragg-Uhler) 0.39
Pseudo-R² (McFadden) 0.31
AIC 94.50
BIC 125.26
exp(Est.) 2.5% 97.5% z val. p
(Intercept) 12219564.46 0.00 Inf 0.01 0.99
Level of integrationFull integration 14.32 2.15 95.29 2.75 0.01
Level of integrationPartial integration 5.15 0.80 33.01 1.73 0.08
Income LevelLower middle income 0.20 0.04 1.10 -1.85 0.06
Income LevelUpper middle income 0.34 0.03 3.50 -0.91 0.36
High burden countryHBC 4.19 1.15 15.33 2.17 0.03
TPT trainingYes 0.00 0.00 Inf -0.01 0.99
TPT trainingDont Know 9.26 0.00 Inf 0.00 1.00
Facility level of careHealth centre 2.28 0.64 8.12 1.27 0.20
Facility level of careDistrict hospital 45366090.11 0.00 Inf 0.01 0.99
Standard errors: MLE

Outcome 3: Adherence to any of the recommendations for other people at risk.

m3 <- glm(any_yes ~ `Level of integration` + `Income Level` + `High burden country` + `TPT training` + `Facility level of care`,
          family = "binomial",
          data = oPaR)
summ(m3, confint = TRUE, exp = TRUE)
Observations 160 (16 missing obs. deleted)
Dependent variable any_yes
Type Generalized linear model
Family binomial
Link logit
𝛘²(9) 52.85
Pseudo-R² (Cragg-Uhler) 0.38
Pseudo-R² (McFadden) 0.25
AIC 178.85
BIC 209.61
exp(Est.) 2.5% 97.5% z val. p
(Intercept) 0.03 0.00 0.39 -2.72 0.01
Level of integrationFull integration 4.00 0.64 24.86 1.49 0.14
Level of integrationPartial integration 1.67 0.28 10.16 0.56 0.58
Income LevelLower middle income 3.29 1.32 8.19 2.56 0.01
Income LevelUpper middle income 0.74 0.23 2.35 -0.50 0.61
High burden countryHBC 3.02 1.22 7.47 2.39 0.02
TPT trainingYes 2.09 0.54 8.13 1.06 0.29
TPT trainingDont Know 8.89 0.65 121.52 1.64 0.10
Facility level of careHealth centre 3.36 1.43 7.85 2.79 0.01
Facility level of careDistrict hospital 33020546.90 0.00 Inf 0.02 0.99
Standard errors: MLE